/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2007 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_DECODER)

#include <trace_log.h>
#include "umc_avs_dec_decompressor.h"
#include "umc_avs_picture_header.h"
#include "umc_avs_mb_info.h"

namespace UMC
{

void AVSDecompressor::ReconstructMotionVectorsPSlice(void)
{
    AVSMVector mvTemp;

    switch (m_pMbInfo->divType)
    {
    case Div_16x16:
        // get the motion vector prediction & reconstruct motion vector
        GetMotionVectorPredictor16x16(PredForward, 0);
        mvTemp = mv_diff[0] + m_mvPred;
        m_pMbInfo->mv[0][0] = mvTemp;
        m_pMbInfo->mv[0][1] = mvTemp;
        m_pMbInfo->mv[0][2] = mvTemp;
        m_pMbInfo->mv[0][3] = mvTemp;
        break;

    case Div_16x8:
        // get the motion vector prediction & reconstruct motion vector
        m_neighbours.pNearest = m_pMbInfoTop;
        m_neighbours.pTop = m_pMbInfoTop;
        m_neighbours.pTopRight = m_pMbInfoTopRight;
        m_neighbours.pTopLeft = m_pMbInfoTopLeft;
        GetMotionVectorPredictor16x8(PredForward, 0);
        mvTemp = mv_diff[0] + m_mvPred;
        m_pMbInfo->mv[0][0] = mvTemp;
        m_pMbInfo->mv[0][1] = mvTemp;

        // get the motion vector prediction & reconstruct motion vector
        m_neighbours.pNearest = m_pMbInfoLeft;
        m_neighbours.pTop = m_pMbInfo;
        m_neighbours.pTopRight = NULL;
        m_neighbours.pTopLeft = m_pMbInfoLeft;
        GetMotionVectorPredictor16x8(PredForward, 2);
        mvTemp = mv_diff[1] + m_mvPred;
        m_pMbInfo->mv[0][2] = mvTemp;
        m_pMbInfo->mv[0][3] = mvTemp;
        break;

    case Div_8x16:
        // get the motion vector prediction & reconstruct motion vector
        m_neighbours.pNearest = m_pMbInfoLeft;
        m_neighbours.pLeft = m_pMbInfoLeft;
        m_neighbours.pTopRight = m_pMbInfoTop;
        m_neighbours.pTopLeft = NULL;
        GetMotionVectorPredictor8x16(PredForward, 0);
        mvTemp = mv_diff[0] + m_mvPred;
        m_pMbInfo->mv[0][0] = mvTemp;
        m_pMbInfo->mv[0][2] = mvTemp;

        // get the motion vector prediction & reconstruct motion vector
        m_neighbours.pNearest = (m_pMbInfoTopRight) ? (m_pMbInfoTopRight) : (m_pMbInfoTop);
        m_neighbours.pLeft = m_pMbInfo;
        m_neighbours.pTopRight = m_pMbInfoTopRight;
        m_neighbours.pTopLeft = m_pMbInfoTop;
        GetMotionVectorPredictor8x16(PredForward, 1);
        mvTemp = mv_diff[1] + m_mvPred;
        m_pMbInfo->mv[0][1] = mvTemp;
        m_pMbInfo->mv[0][3] = mvTemp;
        break;

    default:
        // get the motion vector prediction & reconstruct motion vector
        m_neighbours.pLeft = m_pMbInfoLeft;
        m_neighbours.pTop = m_pMbInfoTop;
        m_neighbours.pTopRight = m_pMbInfoTop;
        m_neighbours.pTopLeft = NULL;
        GetMotionVectorPredictor8x8(PredForward, 0);
        mvTemp = mv_diff[0] + m_mvPred;
        m_pMbInfo->mv[0][0] = mvTemp;

        // get the motion vector prediction & reconstruct motion vector
        m_neighbours.pLeft = m_pMbInfo;
        m_neighbours.pTopRight = m_pMbInfoTopRight;
        m_neighbours.pTopLeft = m_pMbInfoTop;
        GetMotionVectorPredictor8x8(PredForward, 1);
        mvTemp = mv_diff[1] + m_mvPred;
        m_pMbInfo->mv[0][1] = mvTemp;

        // get the motion vector prediction & reconstruct motion vector
        m_neighbours.pLeft = m_pMbInfoLeft;
        m_neighbours.pTop = m_pMbInfo;
        m_neighbours.pTopRight = m_pMbInfo;
        m_neighbours.pTopLeft = NULL;
        GetMotionVectorPredictor8x8(PredForward, 2);
        mvTemp = mv_diff[2] + m_mvPred;
        m_pMbInfo->mv[0][2] = mvTemp;

        // get the motion vector prediction & reconstruct motion vector
        m_neighbours.pLeft = m_pMbInfo;
        m_neighbours.pTopRight = NULL;
        m_neighbours.pTopLeft = m_pMbInfo;
        GetMotionVectorPredictor8x8(PredForward, 3);
        mvTemp = mv_diff[3] + m_mvPred;
        m_pMbInfo->mv[0][3] = mvTemp;
        break;
    }

    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][0].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][0].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][1].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][1].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][2].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][2].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][3].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][3].vector.y);

} // void AVSDecompressor::ReconstructMotionVectorsPSlice(void)

void AVSDecompressor::ReconstructMotionVectorsBSlice(void)
{
    switch (m_pMbInfo->divType)
    {
    case Div_16x16:
        ReconstructMotionVectorsBSlice16x16();
        break;

    case Div_16x8:
        ReconstructMotionVectorsBSlice16x8();
        break;

    case Div_8x16:
        ReconstructMotionVectorsBSlice8x16();
        break;

    default:
        ReconstructMotionVectorsBSlice8x8();
        break;
    }

    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][0].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][0].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][1].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][1].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][2].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][2].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector X", m_pMbInfo->mv[AVS_FORWARD][3].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "FW motion vector Y", m_pMbInfo->mv[AVS_FORWARD][3].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][0].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][0].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][1].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][1].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][2].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][2].vector.y);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector X", m_pMbInfo->mv[AVS_BACKWARD][3].vector.x);
    WRITE_TRACE_LOG(_vec_final_tst, "BW motion vector Y", m_pMbInfo->mv[AVS_BACKWARD][3].vector.y);

} // void AVSDecompressor::ReconstructMotionVectorsBSlice(void)

void AVSDecompressor::ReconstructMotionVectorsBSlice16x16(void)
{
    Ipp8u *pPredType = m_pMbInfo->predType;

    // get the forward motion vector prediction & reconstruct the motion vector
    if (pPredType[0] & PredForward)
    {
        AVSMVector mvTemp;

        GetMotionVectorPredictor16x16(PredForward, 0);
        mvTemp = mv_diff[0] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][0] = mvTemp;
        m_pMbInfo->mv[AVS_FORWARD][1] = mvTemp;
        m_pMbInfo->mv[AVS_FORWARD][2] = mvTemp;
        m_pMbInfo->mv[AVS_FORWARD][3] = mvTemp;
    }

    if (PredForward != pPredType[0])
    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[0])
        {
            GetMotionVectorPredictor16x16(PredBackward, 0);
            mvTemp = mv_diff[0] + m_mvPred;
        }
        // create the symmetrical backward motion vector
        else
        {
            CreateSymmetricalMotionVector(0);
            mvTemp = m_mvPred;

            // clone reference index
            m_pMbInfo->refIdx[AVS_BACKWARD][1] = m_pMbInfo->refIdx[AVS_BACKWARD][0];
            m_pMbInfo->refIdx[AVS_BACKWARD][2] = m_pMbInfo->refIdx[AVS_BACKWARD][0];
            m_pMbInfo->refIdx[AVS_BACKWARD][3] = m_pMbInfo->refIdx[AVS_BACKWARD][0];

            // correct prediction type
            pPredType[0] = PredBiDir;
            pPredType[1] = PredBiDir;
            pPredType[2] = PredBiDir;
            pPredType[3] = PredBiDir;
        }

        m_pMbInfo->mv[AVS_BACKWARD][0] = mvTemp;
        m_pMbInfo->mv[AVS_BACKWARD][1] = mvTemp;
        m_pMbInfo->mv[AVS_BACKWARD][2] = mvTemp;
        m_pMbInfo->mv[AVS_BACKWARD][3] = mvTemp;
    }

} // void AVSDecompressor::ReconstructMotionVectorsBSlice16x16(void)

#define AVS_PREPARE_NEIGHBOURS_16x8_0 \
    m_neighbours.pNearest = m_pMbInfoTop; \
    m_neighbours.pTop = m_pMbInfoTop; \
    m_neighbours.pTopRight = m_pMbInfoTopRight; \
    m_neighbours.pTopLeft = m_pMbInfoTopLeft;

#define AVS_PREPARE_NEIGHBOURS_16x8_1 \
    m_neighbours.pNearest = m_pMbInfoLeft; \
    m_neighbours.pTop = m_pMbInfo; \
    m_neighbours.pTopRight = NULL; \
    m_neighbours.pTopLeft = m_pMbInfoLeft;

void AVSDecompressor::ReconstructMotionVectorsBSlice16x8(void)
{
    Ipp8u *pPredType = m_pMbInfo->predType;
    Ipp32s numMV;

    numMV = 0;
    // get the motion vector prediction & reconstruct motion vector
    if (pPredType[0] & PredForward)
    {
        AVSMVector mvTemp;

        AVS_PREPARE_NEIGHBOURS_16x8_0
        GetMotionVectorPredictor16x8(PredForward, 0);
        mvTemp = mv_diff[numMV++] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][0] = mvTemp;
        m_pMbInfo->mv[AVS_FORWARD][1] = mvTemp;
    }

    // get the motion vector prediction & reconstruct motion vector
    if (pPredType[2] & PredForward)
    {
        AVSMVector mvTemp;

        AVS_PREPARE_NEIGHBOURS_16x8_1
        GetMotionVectorPredictor16x8(PredForward, 2);
        mvTemp = mv_diff[numMV++] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][2] = mvTemp;
        m_pMbInfo->mv[AVS_FORWARD][3] = mvTemp;
    }

    if (PredForward != pPredType[0])
    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[0])
        {
            AVS_PREPARE_NEIGHBOURS_16x8_0
            GetMotionVectorPredictor16x8(PredBackward, 0);
            mvTemp = mv_diff[numMV++] + m_mvPred;
        }
        // create the symmetrical backward motion vector
        else
        {
            CreateSymmetricalMotionVector(0);
            mvTemp = m_mvPred;

            // clone reference index
            m_pMbInfo->refIdx[AVS_BACKWARD][1] = m_pMbInfo->refIdx[AVS_BACKWARD][0];

            // correct prediction type
            pPredType[0] = PredBiDir;
            pPredType[1] = PredBiDir;
        }

        m_pMbInfo->mv[AVS_BACKWARD][0] = mvTemp;
        m_pMbInfo->mv[AVS_BACKWARD][1] = mvTemp;
    }

    if (PredForward != pPredType[2])
    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[2])
        {
            AVS_PREPARE_NEIGHBOURS_16x8_1
            GetMotionVectorPredictor16x8(PredBackward, 2);
            mvTemp = mv_diff[numMV++] + m_mvPred;
        }
        // create the symmetrical backward motion vector
        else
        {
            CreateSymmetricalMotionVector(2);
            mvTemp = m_mvPred;

            // clone reference index
            m_pMbInfo->refIdx[AVS_BACKWARD][3] = m_pMbInfo->refIdx[AVS_BACKWARD][2];

            // correct prediction type
            pPredType[2] = PredBiDir;
            pPredType[3] = PredBiDir;
        }

        m_pMbInfo->mv[AVS_BACKWARD][2] = mvTemp;
        m_pMbInfo->mv[AVS_BACKWARD][3] = mvTemp;
    }

} // void AVSDecompressor::ReconstructMotionVectorsBSlice16x8(void)

#define AVS_PREPARE_NEIGHBOURS_8x16_0 \
    m_neighbours.pNearest = m_pMbInfoLeft; \
    m_neighbours.pLeft = m_pMbInfoLeft; \
    m_neighbours.pTopRight = m_pMbInfoTop; \
    m_neighbours.pTopLeft = NULL; \

#define AVS_PREPARE_NEIGHBOURS_8x16_1 \
    m_neighbours.pNearest = (m_pMbInfoTopRight) ? (m_pMbInfoTopRight) : (m_pMbInfoTop); \
    m_neighbours.pLeft = m_pMbInfo; \
    m_neighbours.pTopRight = m_pMbInfoTopRight; \
    m_neighbours.pTopLeft = m_pMbInfoTop;

void AVSDecompressor::ReconstructMotionVectorsBSlice8x16(void)
{
    Ipp8u *pPredType = m_pMbInfo->predType;
    Ipp32s numMV;

    numMV = 0;
    // get the motion vector prediction & reconstruct motion vector
    if (pPredType[0] & PredForward)
    {
        AVSMVector mvTemp;

        AVS_PREPARE_NEIGHBOURS_8x16_0
        GetMotionVectorPredictor8x16(PredForward, 0);
        mvTemp = mv_diff[numMV++] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][0] = mvTemp;
        m_pMbInfo->mv[AVS_FORWARD][2] = mvTemp;
    }

    // get the motion vector prediction & reconstruct motion vector
    if (pPredType[1] & PredForward)
    {
        AVSMVector mvTemp;

        AVS_PREPARE_NEIGHBOURS_8x16_1
        GetMotionVectorPredictor8x16(PredForward, 1);
        mvTemp = mv_diff[numMV++] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][1] = mvTemp;
        m_pMbInfo->mv[AVS_FORWARD][3] = mvTemp;
    }

    if (PredForward != pPredType[0])
    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[0])
        {
            AVS_PREPARE_NEIGHBOURS_8x16_0
            GetMotionVectorPredictor8x16(PredBackward, 0);
            mvTemp = mv_diff[numMV++] + m_mvPred;
        }
        // create the symmetrical backward motion vector
        else
        {
            CreateSymmetricalMotionVector(0);
            mvTemp = m_mvPred;

            // clone reference index
            m_pMbInfo->refIdx[AVS_BACKWARD][2] = m_pMbInfo->refIdx[AVS_BACKWARD][0];

            // correct prediction type
            pPredType[0] = PredBiDir;
            pPredType[2] = PredBiDir;
        }

        m_pMbInfo->mv[AVS_BACKWARD][0] = mvTemp;
        m_pMbInfo->mv[AVS_BACKWARD][2] = mvTemp;
    }

    if (PredForward != pPredType[1])
    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[1])
        {
            AVS_PREPARE_NEIGHBOURS_8x16_1
            GetMotionVectorPredictor8x16(PredBackward, 1);
            mvTemp = mv_diff[numMV++] + m_mvPred;
        }
        // create the symmetrical backward motion vector
        else
        {
            CreateSymmetricalMotionVector(1);
            mvTemp = m_mvPred;

            // clone reference index
            m_pMbInfo->refIdx[AVS_BACKWARD][3] = m_pMbInfo->refIdx[AVS_BACKWARD][1];

            // correct prediction type
            pPredType[1] = PredBiDir;
            pPredType[3] = PredBiDir;
        }

        m_pMbInfo->mv[AVS_BACKWARD][1] = mvTemp;
        m_pMbInfo->mv[AVS_BACKWARD][3] = mvTemp;
    }

} // void AVSDecompressor::ReconstructMotionVectorsBSlice8x16(void)

#define AVS_PREPARE_NEIGHBOURS_8x8_0 \
    m_neighbours.pLeft = m_pMbInfoLeft; \
    m_neighbours.pTop = m_pMbInfoTop; \
    m_neighbours.pTopRight = m_pMbInfoTop; \
    m_neighbours.pTopLeft = NULL;

#define AVS_PREPARE_NEIGHBOURS_8x8_1 \
    m_neighbours.pLeft = m_pMbInfo; \
    m_neighbours.pTop = m_pMbInfoTop; \
    m_neighbours.pTopRight = m_pMbInfoTopRight; \
    m_neighbours.pTopLeft = m_pMbInfoTop;

#define AVS_PREPARE_NEIGHBOURS_8x8_2 \
    m_neighbours.pLeft = m_pMbInfoLeft; \
    m_neighbours.pTop = m_pMbInfo; \
    m_neighbours.pTopRight = m_pMbInfo; \
    m_neighbours.pTopLeft = NULL;

#define AVS_PREPARE_NEIGHBOURS_8x8_3 \
    m_neighbours.pLeft = m_pMbInfo; \
    m_neighbours.pTop = m_pMbInfo; \
    m_neighbours.pTopRight = NULL; \
    m_neighbours.pTopLeft = m_pMbInfo;

void AVSDecompressor::ReconstructMotionVectorsBSlice8x8(void)
{
    Ipp8u *pPredType = m_pMbInfo->predType;
    Ipp32s numMV;

    numMV = 0;

    // get the motion vector prediction & reconstruct motion vector
    if (PredDirect == pPredType[0])
    {
        ReconstructDirectMotionVector(0);
    }
    else if (pPredType[0] & PredForward)
    {
        AVSMVector mvTemp;

        AVS_PREPARE_NEIGHBOURS_8x8_0
        GetMotionVectorPredictor8x8(PredForward, 0);
        mvTemp = mv_diff[numMV++] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][0] = mvTemp;
    }

    // get the motion vector prediction & reconstruct motion vector
    if (PredDirect == pPredType[1])
    {
        ReconstructDirectMotionVector(1);
    }
    else if (pPredType[1] & PredForward)
    {
        AVSMVector mvTemp;

        AVS_PREPARE_NEIGHBOURS_8x8_1
        GetMotionVectorPredictor8x8(PredForward, 1);
        mvTemp = mv_diff[numMV++] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][1] = mvTemp;
    }

    // get the motion vector prediction & reconstruct motion vector
    if (PredDirect == pPredType[2])
    {
        ReconstructDirectMotionVector(2);
    }
    else if (pPredType[2] & PredForward)
    {
        AVSMVector mvTemp;

        AVS_PREPARE_NEIGHBOURS_8x8_2
        GetMotionVectorPredictor8x8(PredForward, 2);
        mvTemp = mv_diff[numMV++] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][2] = mvTemp;
    }

    // get the motion vector prediction & reconstruct motion vector
    if (PredDirect == pPredType[3])
    {
        ReconstructDirectMotionVector(3);
    }
    else if (pPredType[3] & PredForward)
    {
        AVSMVector mvTemp;

        AVS_PREPARE_NEIGHBOURS_8x8_3
        GetMotionVectorPredictor8x8(PredForward, 3);
        mvTemp = mv_diff[numMV++] + m_mvPred;
        m_pMbInfo->mv[AVS_FORWARD][3] = mvTemp;
    }

    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[0])
        {
            AVS_PREPARE_NEIGHBOURS_8x8_0
            GetMotionVectorPredictor8x8(PredBackward, 0);
            mvTemp = mv_diff[numMV++] + m_mvPred;
            m_pMbInfo->mv[AVS_BACKWARD][0] = mvTemp;
        }
        // create the symmetrical backward motion vector
        else if (PredSym == pPredType[0])
        {
            CreateSymmetricalMotionVector(0);
            m_pMbInfo->mv[AVS_BACKWARD][0] = m_mvPred;

            // correct prediction type
            pPredType[0] = PredBiDir;
        }
    }

    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[1])
        {
            AVS_PREPARE_NEIGHBOURS_8x8_1
            GetMotionVectorPredictor8x8(PredBackward, 1);
            mvTemp = mv_diff[numMV++] + m_mvPred;
            m_pMbInfo->mv[AVS_BACKWARD][1] = mvTemp;
        }
        // create the symmetrical backward motion vector
        else if (PredSym == pPredType[1])
        {
            CreateSymmetricalMotionVector(1);
            m_pMbInfo->mv[AVS_BACKWARD][1] = m_mvPred;

            // correct prediction type
            pPredType[1] = PredBiDir;
        }
    }

    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[2])
        {
            AVS_PREPARE_NEIGHBOURS_8x8_2
            GetMotionVectorPredictor8x8(PredBackward, 2);
            mvTemp = mv_diff[numMV++] + m_mvPred;
            m_pMbInfo->mv[AVS_BACKWARD][2] = mvTemp;
        }
        // create the symmetrical backward motion vector
        else if (PredSym == pPredType[2])
        {
            CreateSymmetricalMotionVector(2);
            m_pMbInfo->mv[AVS_BACKWARD][2] = m_mvPred;

            // correct prediction type
            pPredType[2] = PredBiDir;
        }
    }

    {
        AVSMVector mvTemp;

        // reconstruct the backward motion vector
        if (PredBackward == pPredType[3])
        {
            AVS_PREPARE_NEIGHBOURS_8x8_3
            GetMotionVectorPredictor8x8(PredBackward, 3);
            mvTemp = mv_diff[numMV++] + m_mvPred;
            m_pMbInfo->mv[AVS_BACKWARD][3] = mvTemp;
        }
        // create the symmetrical backward motion vector
        else if (PredSym == pPredType[3])
        {
            CreateSymmetricalMotionVector(3);
            m_pMbInfo->mv[AVS_BACKWARD][3] = m_mvPred;

            // correct prediction type
            pPredType[3] = PredBiDir;
        }
    }

} // void AVSDecompressor::ReconstructMotionVectorsBSlice8x8(void)

#define GET_NEIGHBOUR_MV(vector, dist, neighbour_info, block_num) \
    if ((neighbour_info)->predType[block_num] & predType) \
    { \
        /* get the block reference index */ \
        Ipp32s ind = (neighbour_info)->refIdx[predType - 1][block_num]; \
        /* copy the vector */ \
        vector = (neighbour_info)->mv[predType - 1][block_num]; \
        lastVector = vector; \
        /* get the distance to the reference pixture */ \
        dist = m_blockDist[predType - 1][ind]; \
        availVectors += 1; \
    }

void AVSDecompressor::GetMotionVectorPredictor16x16(eAVSPredType predType, Ipp32s blockNum)
{
    AVSMVector lastVector = {0, 0};
    Ipp32u availVectors = 0;
    AVSMVector mvA, mvB, mvC;
    Ipp32s blockDistA, blockDistB, blockDistC;

    WRITE_TRACE_LOG(_vec_tst, "start prediction for width", 16);
    WRITE_TRACE_LOG(_vec_tst, "start prediction for height", 16);

    //
    // select available neighbour vectors
    //

    mvA.scalar = 0;
    blockDistA = 1;
    if (m_pMbInfoLeft)
    {
        // get top-right block's vector of A macroblock
        GET_NEIGHBOUR_MV(mvA, blockDistA,
                         m_pMbInfoLeft, 1)
    }

    mvB.scalar = 0;
    blockDistB = 1;
    mvC.scalar = 0;
    blockDistC = 1;
    if (m_pMbInfoTop)
    {
        // get bottom-left block's vector of B macroblock
        GET_NEIGHBOUR_MV(mvB, blockDistB,
                         m_pMbInfoTop, 2)

        // get bottom-left block's vector of C macroblock
        if (m_pMbInfoTopRight)
        {
            GET_NEIGHBOUR_MV(mvC, blockDistC,
                             m_pMbInfoTopRight, 2)
        }
        // get bottom-right block's vector of D macroblock
        else if (m_pMbInfoTopLeft)
        {
            GET_NEIGHBOUR_MV(mvC, blockDistC,
                             m_pMbInfoTopLeft, 3)
        }
    }

    //
    // calculate prediction for the current block
    //

    // step 1: available only one neighbour reference
    if (1 == availVectors)
    {
        m_mvPred = lastVector;
    }
    // step 3: perform full calculation
    else
    {
        Ipp32s blockDist;

        blockDist = m_blockDist[predType - 1][m_pMbInfo->refIdx[predType - 1][blockNum]];
        GetMotionVectorPredictor(mvA, mvB, mvC,
                                 blockDist,
                                 blockDistA, blockDistB, blockDistC);
    }

    WRITE_TRACE_LOG(_vec_tst, "motion vector pred X", m_mvPred.vector.x);
    WRITE_TRACE_LOG(_vec_tst, "motion vector pred Y", m_mvPred.vector.y);

} // void AVSDecompressor::GetMotionVectorPredictor16x16(eAVSPredType predType, Ipp32s blockNum)

void AVSDecompressor::GetMotionVectorPredictor16x8(eAVSPredType predType, Ipp32s blockNum)
{
    AVSMVector lastVector = {0, 0};
    Ipp32u availVectors = 0;
    AVSMVector mvA, mvB, mvC;
    Ipp32s blockDistA, blockDistB, blockDistC;

    WRITE_TRACE_LOG(_vec_tst, "start prediction for width", 16);
    WRITE_TRACE_LOG(_vec_tst, "start prediction for height", 8);

    //
    // step 1. select available neighbour vectors
    //

    mvA.scalar = 0;
    blockDistA = 1;
    if (m_pMbInfoLeft)
    {
        // get A block
        GET_NEIGHBOUR_MV(mvA, blockDistA,
                         m_pMbInfoLeft, blockNum + 1)
    }

    mvB.scalar = 0;
    blockDistB = 1;
    mvC.scalar = 0;
    blockDistC = 1;
    if (m_neighbours.pTop)
    {
        // get B macro
        GET_NEIGHBOUR_MV(mvB, blockDistB,
                         m_neighbours.pTop, (blockNum + 2) % 4)

        // get C block
        if (m_neighbours.pTopRight)
        {
            GET_NEIGHBOUR_MV(mvC, blockDistC,
                             m_neighbours.pTopRight, 2)
        }
        // get D block
        else if (m_neighbours.pTopLeft)
        {
            GET_NEIGHBOUR_MV(mvC, blockDistC,
                             m_neighbours.pTopLeft, (blockNum + 3) % 4)
        }
    }

    if (1 == availVectors)
    {
        m_mvPred = lastVector;
    }
    else
    {
        Ipp32s nearBlockNum = (blockNum >> 1) + 2;

        // step 2: if the nearest block has the same index,
        // then we just copy the corresponding vector from this block
        if ((m_neighbours.pNearest) &&
            (m_neighbours.pNearest->predType[nearBlockNum] & predType) &&
            (m_neighbours.pNearest->refIdx[predType - 1][nearBlockNum] ==
             m_pMbInfo->refIdx[predType - 1][blockNum]))
        {
            m_mvPred = m_neighbours.pNearest->mv[predType - 1][nearBlockNum];
        }
        // setp 3: perform full calculation
        else
        {
            Ipp32s blockDist;

            blockDist = m_blockDist[predType - 1][m_pMbInfo->refIdx[predType - 1][blockNum]];
            GetMotionVectorPredictor(mvA, mvB, mvC,
                                     blockDist,
                                     blockDistA, blockDistB, blockDistC);
        }
    }

    WRITE_TRACE_LOG(_vec_tst, "motion vector pred X", m_mvPred.vector.x);
    WRITE_TRACE_LOG(_vec_tst, "motion vector pred Y", m_mvPred.vector.y);

} // void AVSDecompressor::GetMotionVectorPredictor16x8(eAVSPredType predType, Ipp32s blockNum)

void AVSDecompressor::GetMotionVectorPredictor8x16(eAVSPredType predType, Ipp32s blockNum)
{
    AVSMVector lastVector = {0, 0};
    Ipp32u availVectors = 0;
    AVSMVector mvA, mvB, mvC;
    Ipp32s blockDistA, blockDistB, blockDistC;

    WRITE_TRACE_LOG(_vec_tst, "start prediction for width", 8);
    WRITE_TRACE_LOG(_vec_tst, "start prediction for height", 16);

    //
    // step 1. select available neighbour vectors
    //

    mvA.scalar = 0;
    blockDistA = 1;
    if (m_neighbours.pLeft)
    {
        // get A block
        GET_NEIGHBOUR_MV(mvA, blockDistA,
                         m_neighbours.pLeft, blockNum + 1)
    }

    mvB.scalar = 0;
    blockDistB = 1;
    mvC.scalar = 0;
    blockDistC = 1;
    if (m_pMbInfoTop)
    {
        // get B macro
        GET_NEIGHBOUR_MV(mvB, blockDistB,
                         m_pMbInfoTop, blockNum + 2)

        // get C block
        if (m_neighbours.pTopRight)
        {
            GET_NEIGHBOUR_MV(mvC, blockDistC,
                             m_neighbours.pTopRight, 3 - blockNum)
        }
        // get D block
        else if (m_neighbours.pTopLeft)
        {
            GET_NEIGHBOUR_MV(mvC, blockDistC,
                             m_neighbours.pTopLeft, 3 - blockNum)
        }
    }

    if (1 == availVectors)
    {
        m_mvPred = lastVector;
    }
    else
    {
        Ipp32s nearBlockNum = blockNum + 1;

        // step 2: if the nearest block has the same index,
        // then we just copy the corresponding vector from this block
        if ((m_neighbours.pNearest) &&
            (m_neighbours.pNearest->predType[nearBlockNum] & predType) &&
            (m_neighbours.pNearest->refIdx[predType - 1][nearBlockNum] ==
             m_pMbInfo->refIdx[predType - 1][blockNum]))
        {
            m_mvPred = m_neighbours.pNearest->mv[predType - 1][nearBlockNum];
        }
        // setp 3: perform full calculation
        else
        {
            Ipp32s blockDist;

            blockDist = m_blockDist[predType - 1][m_pMbInfo->refIdx[predType - 1][blockNum]];
            GetMotionVectorPredictor(mvA, mvB, mvC,
                                     blockDist,
                                     blockDistA, blockDistB, blockDistC);
        }
    }

    WRITE_TRACE_LOG(_vec_tst, "motion vector pred X", m_mvPred.vector.x);
    WRITE_TRACE_LOG(_vec_tst, "motion vector pred Y", m_mvPred.vector.y);

} // void AVSDecompressor::GetMotionVectorPredictor8x16(eAVSPredType predType, Ipp32s blockNum)

void AVSDecompressor::GetMotionVectorPredictor8x8(eAVSPredType predType, Ipp32s blockNum)
{
    AVSMVector lastVector = {0, 0};
    Ipp32u availVectors = 0;
    AVSMVector mvA, mvB, mvC;
    Ipp32s blockDistA, blockDistB, blockDistC;

    WRITE_TRACE_LOG(_vec_tst, "start prediction for width", 8);
    WRITE_TRACE_LOG(_vec_tst, "start prediction for height", 8);

    //
    // step 1. select available neighbour vectors
    //

    mvA.scalar = 0;
    blockDistA = 1;
    if (m_neighbours.pLeft)
    {
        // get A block
        GET_NEIGHBOUR_MV(mvA, blockDistA,
                         m_neighbours.pLeft, blockNum ^ 1)
    }

    mvB.scalar = 0;
    blockDistB = 1;
    mvC.scalar = 0;
    blockDistC = 1;
    if (m_neighbours.pTop)
    {
        // get B macro
        GET_NEIGHBOUR_MV(mvB, blockDistB,
                         m_neighbours.pTop, (blockNum + 2) % 4)

        // get C block
        if (m_neighbours.pTopRight)
        {
            GET_NEIGHBOUR_MV(mvC, blockDistC,
                             m_neighbours.pTopRight, 3 - blockNum)
        }
        // get D block
        else if (m_neighbours.pTopLeft)
        {
            GET_NEIGHBOUR_MV(mvC, blockDistC,
                             m_neighbours.pTopLeft, 3 - blockNum)
        }
    }

    if (1 == availVectors)
    {
        m_mvPred = lastVector;
    }
    else
    {
        Ipp32s blockDist;

        blockDist = m_blockDist[predType - 1][m_pMbInfo->refIdx[predType - 1][blockNum]];
        GetMotionVectorPredictor(mvA, mvB, mvC,
                                 blockDist,
                                 blockDistA, blockDistB, blockDistC);
    }

    WRITE_TRACE_LOG(_vec_tst, "motion vector pred X", m_mvPred.vector.x);
    WRITE_TRACE_LOG(_vec_tst, "motion vector pred Y", m_mvPred.vector.y);

} // void AVSDecompressor::GetMotionVectorPredictor8x8(eAVSPredType predType, Ipp32s blockNum)

inline
Ipp32s ScaleValue(Ipp32s value, Ipp32s blockDist, Ipp32s otherBlockDist)
{
    Ipp32s signExtended = value >> 31;

    // get the absolute value
    value = (value ^ signExtended) - signExtended;

    // scale value
    value = ((value * blockDist) * (512 / otherBlockDist) + 256) >> 9;

    // restore the sign of the value
    value = (value + signExtended) ^ signExtended;

    return value;

} // Ipp32s ScaleValue(Ipp32s value, Ipp32s blockDist, Ipp32s otherBlockDist)

#define AvsAbs(value) \
    ((0 < (value)) ? (value) : (-(value)))

inline
Ipp32s VectorDistance(AVSMVector mvOne, AVSMVector mvTwo)
{
    Ipp32s dist;

    dist = AvsAbs(mvOne.vector.x - mvTwo.vector.x) +
           AvsAbs(mvOne.vector.y - mvTwo.vector.y);

    return dist;

} // Ipp32s VectorDistance(AVSMVector mvOne, AVSMVector mvTwo)

void AVSDecompressor::GetMotionVectorPredictor(AVSMVector mvA,
                                               AVSMVector mvB,
                                               AVSMVector mvC,
                                               Ipp32s blockDist,
                                               Ipp32s blockDistA,
                                               Ipp32s blockDistB,
                                               Ipp32s blockDistC)
{
    Ipp32s distAB, distBC, distCA;
    Ipp32s median;

    // scale motion vectors
    mvA.vector.x = (Ipp16s) ScaleValue(mvA.vector.x, blockDist, blockDistA);
    mvA.vector.y = (Ipp16s) ScaleValue(mvA.vector.y, blockDist, blockDistA);
    mvB.vector.x = (Ipp16s) ScaleValue(mvB.vector.x, blockDist, blockDistB);
    mvB.vector.y = (Ipp16s) ScaleValue(mvB.vector.y, blockDist, blockDistB);
    mvC.vector.x = (Ipp16s) ScaleValue(mvC.vector.x, blockDist, blockDistC);
    mvC.vector.y = (Ipp16s) ScaleValue(mvC.vector.y, blockDist, blockDistC);

    // get distance between vectors
    distAB = VectorDistance(mvA, mvB);
    distBC = VectorDistance(mvB, mvC);
    distCA = VectorDistance(mvC, mvA);

    // get the Median()
    median = distAB + distBC + distCA -
             IPP_MIN(distAB, IPP_MIN(distBC, distCA)) -
             IPP_MAX(distAB, IPP_MAX(distBC, distCA));

    if (distAB == median)
    {
        m_mvPred = mvC;
    }
    else if (distBC == median)
    {
        m_mvPred = mvA;
    }
    else
    {
        m_mvPred = mvB;
    }

} // void AVSDecompressor::GetMotionVectorPredictor(AVSMVector mvA,

void AVSDecompressor::CreateSymmetricalMotionVector(Ipp32s blockNum)
{
    AVSMVector mvFw;
    Ipp32s DistanceMul;

    // calculate vector distance
    DistanceMul = m_blockDist[AVS_BACKWARD][0] * (512 / m_blockDist[AVS_FORWARD][0]);

    // compute the vector
    mvFw = m_pMbInfo->mv[AVS_FORWARD][blockNum];
    m_mvPred.vector.x = (Ipp16s) -((mvFw.vector.x * DistanceMul + 256) >> 9);
    m_mvPred.vector.y = (Ipp16s) -((mvFw.vector.y * DistanceMul + 256) >> 9);

} // void AVSDecompressor::CreateSymmetricalMotionVector(Ipp32s blockNum)

} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_DECODER)
